package vistas;

import java.util.*;
import java.io.*;
import java.lang.reflect.*;
import javax.swing.*;
import javax.imageio.ImageIO;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Iterator;
import java.util.List;

import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

import api.API;
import api.ControlDispositivos;
import api.ControlReflection;
import api.ControlReflection.Atributo;
import api.ControlReflection.Metodo;
import api.Dispositivo;

import dominioTanque.Bomba;
import dominioTanque.Tanque;

@SuppressWarnings("serial")
public class VentanaDispositivos extends JFrame implements MouseListener,ActionListener{
	
	//Componentes para la carga de dispositivos
	private PlanoEdificio plano;

	//Componentes del panelDatos
	private DefaultComboBoxModel modelCBDispositivo;
	private JLabel tipoDisp;
	private JLabel idDisp;
	private JLabel pisoDisp;
	private JPanel imagenDisp;
	
	//Componentes del panelAtributos
	private DefaultListModel modelListAtributos;
	private JList listAtributos;
	private JLabel tipoAtributo;
	private JLabel valorAtributo;
	
	//Componentes del panelMetodos
	private DefaultListModel modelListMetodos;
	private JList listMetodos;
	private JLabel tipoReturn;
	private Metodo metodoActual;
	
	private ControlReflection cr = new ControlReflection();
	
	public VentanaDispositivos(PlanoEdificio plano){
		super("Dispositivos");	
		this.plano = plano;
		this.setPanelPrincipal();
		this.agregarPanelDatos();
		this.agregarPanelAtributos();
		this.agregarPanelMetodos();
		this.actualizar();
		this.pack();
		this.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
	}
	
	public void setPlano(PlanoEdificio plano){
		this.plano = plano;
		this.actualizar();
	}

	private void setPanelPrincipal() {
		JPanel panelPrincipal = new JPanel();
		panelPrincipal.setLayout(new GridBagLayout());
		this.setContentPane(panelPrincipal);
	}
	
	private void agregarPanelDatos() {
		JPanel panel = new JPanel();
		panel.setLayout(new GridBagLayout());
		
		//JLabels para los textos
		JLabel labelTipo = new JLabel("Tipo: ");
		JLabel labelId = new JLabel("Id: ");
		JLabel labelPiso = new JLabel("Piso: ");
		JLabel labelCBSeleccion = new JLabel("Dispositivos");
		this.tipoDisp = new JLabel("");
		this.idDisp = new JLabel("");
		this.pisoDisp = new JLabel("");
		this.imagenDisp = new JPanel(){
			public void paint(Graphics g){
				Dispositivo dispositivo = (Dispositivo)modelCBDispositivo.getSelectedItem();
				if (dispositivo!=null) {
					Image imagen = new ImageIcon(dispositivo.getPathIcono()).getImage();
					if (imagen != null)	g.drawImage(imagen, 10, 10, 80, 80, this);
					} else g.setColor(this.getBackground());
			}
		};
		this.imagenDisp.setPreferredSize(new Dimension(100,100));
		
		//JComboBox para elegir el dispositivo
		this.modelCBDispositivo = new DefaultComboBoxModel();
		JComboBox cbDispositivos = new JComboBox(this.modelCBDispositivo);
		cbDispositivos.addActionListener(this);
		this.cargarDispositivos(cbDispositivos);
		this.actualizar();
		
		//JButton para ejecutar el metodo seleccionado
		JButton btnEliminar = new JButton("Eliminar"){
			//Pongo que hacer cuando se hace clic
			protected void processMouseEvent(MouseEvent event){
				if (event.getID() == MouseEvent.MOUSE_CLICKED){
					this.doClick();
					Dispositivo disp = (Dispositivo)modelCBDispositivo.getSelectedItem();
					modelCBDispositivo.removeElement(disp);
					plano.eliminarDispositivo(disp);
					ControlDispositivos.obtenerInstancia().eliminarDispositivo(disp);
					API.obtenerInstancia().quitarNotificador(disp.getNotificador());
				}
			}
		};
		
		//Agrego todo al panel
		GridBagConstraints con = new GridBagConstraints();
		con.anchor = GridBagConstraints.CENTER;
		con.gridy = 0;
		con.gridx = 0;
		panel.add(labelCBSeleccion,con);
		con.gridx = 1;
		con.gridheight = 3;
		panel.add(this.imagenDisp,con);
		
		con.gridy = 1;
		con.gridx = 0;
		con.gridheight = 2;
		panel.add(cbDispositivos,con);
		con.gridheight = 1;
		con.gridx = 2;
		panel.add(labelTipo,con);
		con.gridx = 3;
		panel.add(this.tipoDisp,con);
		con.anchor = GridBagConstraints.NORTHWEST;
		con.gridy = 2;
		con.gridx = 4;
		panel.add(btnEliminar,con);
		
		con.anchor = GridBagConstraints.CENTER;
		con.gridy = 2;
		con.gridx = 2;
		panel.add(labelId,con);
		con.gridx = 3;
		panel.add(this.idDisp,con);
		
		con.gridy = 3;
		con.gridx = 2;
		panel.add(labelPiso,con);
		con.gridx = 3;
		panel.add(this.pisoDisp,con);
		
		con.gridy = 0;
		con.gridx = 0;
		con.gridwidth = 3;
		con.fill = GridBagConstraints.HORIZONTAL;
		this.getContentPane().add(panel,con);
	}
	
	private void agregarPanelAtributos() {
		JPanel panel = new JPanel();
		panel.setLayout(new GridBagLayout());
		
		//JLabel para los titulos de las cosas
		JLabel labelLAtributos = new JLabel("Atributos");
		JLabel labelTipo = new JLabel("Tipo: ");
		JLabel labelValor = new JLabel("Valor: ");
		this.tipoAtributo = new JLabel("");
		this.valorAtributo = new JLabel("");
		
		//JList para los atributos
		this.modelListAtributos = new DefaultListModel();
		this.listAtributos = new JList(modelListAtributos);
		this.listAtributos.addMouseListener(this);
		
		
		
		//Agrego todo al panel
		GridBagConstraints con = new GridBagConstraints();
		con.anchor = GridBagConstraints.CENTER;
		con.gridy = 0;
		con.gridx = 0;
		panel.add(labelLAtributos,con);
		
		con.gridy = 1;
		con.gridheight = 3;
		JScrollPane scrollAtributos = new JScrollPane(this.listAtributos);
		scrollAtributos.setPreferredSize(new Dimension(200,98));
		panel.add(scrollAtributos,con);
		
		con.gridy = 1;
		con.gridheight = 1;
		con.gridx = 1;
		panel.add(labelTipo,con);
		con.gridx = 2;
		panel.add(this.tipoAtributo,con);
		
		con.gridy = 3;
		con.gridx = 1;
		panel.add(labelValor,con);
		con.gridx = 2;
		panel.add(this.valorAtributo,con);
		
		con.gridy = 1;
		con.gridx = 0;
		this.getContentPane().add(panel,con);
	}
	
	private void agregarPanelMetodos() {
		JPanel panel = new JPanel();
		panel.setLayout(new GridBagLayout());
		
		//JLabel para los titulos de las cosas
		JLabel labelLMetodos = new JLabel("Metodos");
		JLabel labelTipoReturn = new JLabel("Tipo devuelto: ");
		//JLabel labelParametros = new JLabel("Parametros:");
		this.tipoReturn = new JLabel("");
		
		//JList para la lista de metodos
		this.modelListMetodos = new DefaultListModel();
		this.listMetodos = new JList(modelListMetodos);
		this.listMetodos.addMouseListener(this);
			
		//JButton para ejecutar el metodo seleccionado
		JButton ejecutarMetodo = new JButton("Ejecutar"){
			//Pongo que hacer cuando se hace clic
			protected void processMouseEvent(MouseEvent event){
				if (event.getID() == MouseEvent.MOUSE_CLICKED){
					this.doClick();
					if (metodoActual != null){
						Dispositivo disp = (Dispositivo)modelCBDispositivo.getSelectedItem();
						cr.ejecutar(disp.getNotificador(),metodoActual);
						cargarDatosAtributo((Atributo)listAtributos.getSelectedValue());
					}
				}
			}
		};
		
		//Agrego todo al panel
		GridBagConstraints con = new GridBagConstraints();
		con.anchor = GridBagConstraints.CENTER;
		con.gridy = 0;
		con.gridx = 0;
		panel.add(labelLMetodos,con);
		
		con.gridy = 1;
		con.gridheight = 3;
		JScrollPane scrollMetodos = new JScrollPane(this.listMetodos);
		scrollMetodos.setPreferredSize(new Dimension(200,98));
		panel.add(scrollMetodos,con);
		
		con.gridy = 1;
		con.gridheight = 1;
		con.gridx = 1;
		panel.add(labelTipoReturn,con);
		con.gridx = 2;
		panel.add(this.tipoReturn,con);
		
		con.gridy = 3;
		con.gridx = 1;
		con.gridwidth = 2;
		panel.add(ejecutarMetodo,con);
		
		con.gridy = 1;
		con.gridx = 1;		
		this.getContentPane().add(panel,con);
	}

	//Metodos para cargar el contenido de los ComboBox segun lo que se elige
	private void cargarDispositivos(JComboBox comboBox){
		Iterator<Dispositivo> itDispositivos = this.plano.getDispositivos().iterator();
		Dispositivo d;
		while (itDispositivos.hasNext()){
			d = itDispositivos.next();
			comboBox.addItem(d);
		}	
	}
	
	public void actionPerformed(ActionEvent arg0) {
		DefaultComboBoxModel cbModel = (DefaultComboBoxModel)((JComboBox)arg0.getSource()).getModel();
		if (cbModel == this.modelCBDispositivo){
			this.actualizar();
		}
	}

	private void cargarDatosDisp(Dispositivo dispSeleccionado) {
		if (dispSeleccionado != null){
			this.tipoDisp.setText(dispSeleccionado.getNotificador().getClass().getSimpleName());
			this.idDisp.setText(dispSeleccionado.getId());
			this.pisoDisp.setText(dispSeleccionado.getPiso());
		}
		this.pack();
	}

	private void cargarAtributos(Dispositivo dispSeleccionado) {
		if (this.modelListAtributos == null) this.modelListAtributos = new DefaultListModel();
		this.modelListAtributos.clear();
		this.cargarDatosAtributo(null);
		
		if (dispSeleccionado != null){
			List<Atributo> atributos = cr.getAtributosPropios(dispSeleccionado.getNotificador().getClass(),false);
			Iterator<Atributo> itF = atributos.iterator();
			while(itF.hasNext()) this.modelListAtributos.addElement(itF.next());
		}
	}
	
	private void cargarMetodos(Dispositivo dispSeleccionado) {
		if (this.modelListMetodos == null) this.modelListMetodos = new DefaultListModel();
		this.modelListMetodos.clear();
		this.cargarDatosMetodo(null);
		this.metodoActual = null;
		
		if (dispSeleccionado != null){
			List<Metodo> metodos = cr.getMetodosPropios(dispSeleccionado.getNotificador().getClass(),false);
			Iterator<Metodo> itF = metodos.iterator();
			while(itF.hasNext()) this.modelListMetodos.addElement(itF.next());
		}
	}

	public void mouseClicked(MouseEvent arg0) {
		if (arg0.getID() == MouseEvent.MOUSE_CLICKED){
			if (arg0.getSource() == this.listAtributos){
				if (this.listAtributos.getComponentCount() > 0) cargarDatosAtributo((Atributo)this.listAtributos.getSelectedValue());
			} else if (arg0.getSource() == this.listMetodos) {
				if (this.listMetodos.getComponentCount() > 0) cargarDatosMetodo((Metodo)this.listMetodos.getSelectedValue());
			}
		}
	}

	private void cargarDatosAtributo(Atributo atributo) {
		if (atributo != null){
			this.tipoAtributo.setText(atributo.getAtributo().getType().getSimpleName());
			Dispositivo disp = (Dispositivo)this.modelCBDispositivo.getSelectedItem();
			Object valor = cr.obtenerValor(disp.getNotificador(), atributo);
			this.valorAtributo.setText(valor.toString());
		} else {
			if (this.tipoAtributo != null) this.tipoAtributo.setText("");
			if (this.valorAtributo != null) this.valorAtributo.setText("");
		}
		this.pack();
	}
	
	private void cargarDatosMetodo(Metodo metodo) {
		if (metodo != null){
			this.metodoActual = metodo;
			this.tipoReturn.setText(metodo.getTipoReturn().getSimpleName());
		} else {
			if (this.tipoReturn != null) this.tipoReturn.setText("");
		}
		this.pack();
	}

	public void seleccionarDispositivo(Dispositivo dispositivo){
		this.modelCBDispositivo.setSelectedItem(dispositivo);
		actualizar();
	}
	
	private void actualizar() {
		Dispositivo disp = (Dispositivo)this.modelCBDispositivo.getSelectedItem();
		this.cargarDatosDisp(disp);
		this.cargarAtributos(disp);
		this.cargarMetodos(disp);
		this.pack();
	}
	
	public void mouseEntered(MouseEvent arg0) {}
	public void mouseExited(MouseEvent arg0) {}
	public void mousePressed(MouseEvent arg0) {}
	public void mouseReleased(MouseEvent arg0) {}
}